////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxchiiqutilshandler.cpp
/// @brief Implements the CAMX Chi IQ Utils Handler.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxchiiqutilshandler.h"
#include "chiipedefs.h"
#include "NcLibWarp.h"

#undef LOG_TAG
#define LOG_TAG "CHIIQUTILS"

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CalculateInverseGrid
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult CalculateInverseGrid(
    CHIIQUTILSPARAMS* pChiIQUtilsParams)
{
    CDKResult result = CDKResultSuccess;
    BOOL      retVal = TRUE;

    CAMX_ASSERT(NULL != pChiIQUtilsParams);
    CAMX_ASSERT(NULL != pChiIQUtilsParams->pInputData);
    CAMX_ASSERT(NULL != pChiIQUtilsParams->pOutputData);

    IPEICAInverGridInput*    pInverGridInput  = reinterpret_cast<IPEICAInverGridInput*>(pChiIQUtilsParams->pInputData);
    IPEICAInverseGridOutput* pInverGridOutput = reinterpret_cast<IPEICAInverseGridOutput*>(pChiIQUtilsParams->pOutputData);

    ///< Initialize reverse grid structures used by NcLib
    NcLibWarpReverseGridDirectionIn reversegridIn;
    memset(&reversegridIn, 0, sizeof(NcLibWarpReverseGridDirectionIn));

    reversegridIn.numRows                                    = pInverGridInput->numRows;
    reversegridIn.numColumns                                 = pInverGridInput->numColumns;
    reversegridIn.dstCoords                                  = reinterpret_cast<NcLibWarpGridCoord*>
                                                                                (pInverGridInput->dstGridArray);
    reversegridIn.srcGridColumnCoords                        = pInverGridInput->srcGridColumn;
    reversegridIn.srcGridRowCoords                           = pInverGridInput->srcGridRow;
    reversegridIn.inputTriangulationType                     = static_cast<NcLibUniformGridTriangulation>
                                                                           (pInverGridInput->inputTriangulationType);
    reversegridIn.reversedGridNumColumns                     = pInverGridInput->reversedGridNumColumns;
    reversegridIn.reversedGridNumRows                        = pInverGridInput->reversedGridNumRows;
    reversegridIn.reversedGridSourceTopLeft.x                = pInverGridInput->reversedGridSourceTopLeftX;
    reversegridIn.reversedGridSourceTopLeft.y                = pInverGridInput->reversedGridSourceTopLeftY;
    reversegridIn.reversedGridSourceBottomRight.x            = pInverGridInput->reversedGridSourceBottomRightX;
    reversegridIn.reversedGridSourceBottomRight.y            = pInverGridInput->reversedGridSourceBottomRightY;
    reversegridIn.reversedGridTransformDefinedOn.heightLines = pInverGridInput->transformDefinedOnHeight;
    reversegridIn.reversedGridTransformDefinedOn.widthPixels = pInverGridInput->transformDefinedOnWidth;
    reversegridIn.useExtraCalcsDuringExtrpolation            = pInverGridInput->useExtraCalcsDuringExtrapolation;

    LOG_VERBOSE(CamxLogGroupChi,
                "Inverse grid: in row %u, in column %u, triangulation %d, out row %u,"
                "out column %u, topLeft x %.6lf, topLeft y %.6lf, bottomRight x %.6lf,"
                "bottomRight y %.6lf, width %u, height %u, extp %d",
                reversegridIn.numRows,
                reversegridIn.numColumns,
                reversegridIn.inputTriangulationType,
                reversegridIn.reversedGridNumRows,
                reversegridIn.reversedGridNumColumns,
                reversegridIn.reversedGridSourceTopLeft.x,
                reversegridIn.reversedGridSourceTopLeft.y,
                reversegridIn.reversedGridSourceBottomRight.x,
                reversegridIn.reversedGridSourceBottomRight.y,
                reversegridIn.reversedGridTransformDefinedOn.widthPixels,
                reversegridIn.reversedGridTransformDefinedOn.heightLines,
                reversegridIn.useExtraCalcsDuringExtrpolation);

    NcLibWarpGrid outputGrid;
    memset(&outputGrid, 0, sizeof(NcLibWarpGrid));

    outputGrid.grid = reinterpret_cast<NcLibWarpGridCoord*>
        (CAMX_CALLOC(sizeof(NcLibWarpGridCoord) * ICAGridTransformWidth * ICAGridTransformHeight));

    if (NULL == outputGrid.grid)
    {
        LOG_ERROR(CamxLogGroupChi, "Memory alloc failed for out grid array");
        result = CDKResultEFailed;
    }

    NcLibWarpReverseGridStatistics reversegridstats;
    memset(&reversegridstats, 0, sizeof(NcLibWarpReverseGridStatistics));

    if (CDKResultSuccess == result)
    {
        retVal = NcLibWarpReverseGridDirection(&reversegridIn, &outputGrid, &reversegridstats);
        result = retVal ? CDKResultEFailed : CDKResultSuccess;
    }

    if (CDKResultSuccess == result)
    {
        ///< Reverse grid output translation
        pInverGridOutput->gridOutput.gridTransformEnable      = outputGrid.enable;
        pInverGridOutput->gridOutput.reuseGridTransform       = 0; // not handled currently
        pInverGridOutput->gridOutput.transformDefinedOnHeight = outputGrid.transformDefinedOn.heightLines;
        pInverGridOutput->gridOutput.transformDefinedOnWidth  = outputGrid.transformDefinedOn.widthPixels;
        pInverGridOutput->extrapolationPercentage             = reversegridstats.extrapolationPercentage;

        for (UINT idx = 0; idx < (ICAGridTransformHeight * ICAGridTransformWidth); idx++)
        {
            pInverGridOutput->gridOutput.gridTransformArray[idx].x = outputGrid.grid[idx].x;
            pInverGridOutput->gridOutput.gridTransformArray[idx].y = outputGrid.grid[idx].y;
        }
    }
    else
    {
        LOG_ERROR(CamxLogGroupChi, "InverseGrid calculation failed");
    }

    CAMX_FREE(outputGrid.grid);
    outputGrid.grid = NULL;

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ProcessChiIQUtils
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ProcessChiIQUtils(
    CHIIQUTILSPARAMS* pChiIQUtilsParams)
{
    CDKResult result = CDKResultSuccess;

    if ((NULL == pChiIQUtilsParams)             ||
        (NULL == pChiIQUtilsParams->pInputData) ||
        (NULL == pChiIQUtilsParams->pOutputData))
    {
        LOG_ERROR(CamxLogGroupChi, "Invalid IQ Utils parameters");
        result = CDKResultEInvalidPointer;
    }
    else
    {
        switch (pChiIQUtilsParams->paramType)
        {
            case CHIIQUTILSPARAMSTYPE::IQUtilsCalculateInverseGrid:
                LOG_VERBOSE(CamxLogGroupChi, "IQUtilsCalculateInverseGrid Type");
                result = CalculateInverseGrid(pChiIQUtilsParams);
                break;

            default:
                LOG_VERBOSE(CamxLogGroupChi, "Unknown IQ utility");
                result = CDKResultEUnsupported;
                break;
        }
    }

    if (CDKResultSuccess != result)
    {
        LOG_ERROR(CamxLogGroupChi, "Process Chi IQ Utils failed result %d", result);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiIQUtilsGet
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CDK_VISIBILITY_PUBLIC VOID ChiIQUtilsGet(
    CHIIQUTILS* pChiIQUtils)
{
    if (NULL != pChiIQUtils)
    {
        pChiIQUtils->pProcessChiIQUtils = ProcessChiIQUtils;
    }
}
#ifdef __cplusplus
}
#endif // __cplusplus
